﻿/**
 * Copyright (C) 2011 original author and authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace NGuice.Inject.Internal.Util
{
    public static class Lists
    {
        public static List<E> NewArrayList<E>()
        {
            return new List<E>();
        }

        public static List<E> NewArrayList<E>(params E[] elements)
        {
            // Avoid integer overflow when a large array is passed in
            int capacity = ComputeArrayListCapacity(elements.Length);
            List<E> list = new List<E>(capacity);
            list.AddRange(elements);
            return list;
        }

        static int ComputeArrayListCapacity(int arraySize)
        {
            Preconditions.CheckArgument(arraySize >= 0);

            // TODO: Figure out the right behavior, and document it
            return (int)Math.Min(5L + arraySize + (arraySize / 10), Int32.MaxValue);
        }

        public static List<E> NewArrayList<E>(IEnumerable<E> elements)
        {
            // Let ArrayList's sizing logic work, if possible
            List<E> list = new List<E>();
            list.AddRange(elements);
            return list;
        }

        public static List<E> NewArrayList<E>(IEnumerator<E> elements)
        {
            // Let ArrayList's sizing logic work, if possible
            List<E> list = new List<E>();
            while (elements.MoveNext())
            {
                list.Add(elements.Current);
            }
            return list;
        }

        public static List<E> NewArrayList<E>(E first, E[] rest)
        {
            List<E> result = new List<E>(rest.Length + 1);
            result.Add(first);
            foreach (E element in rest)
            {
                result.Add(element);
            }
            return result;
        }

        /// <summary>
        /// 计算数组的哈希码
        /// </summary>
        public static int HashCode(params object[] a)
        {
            if (a == null)
                return 0;
            int result = 1;
            foreach (object element in a)
                result = 31 * result + (element == null ? 0 : element.GetHashCode());
            return result;
        }

        public static IList<T> Concat<T>(IList<T> a, IList<T> b)
        {
            Preconditions.CheckNotNull(a);
            Preconditions.CheckNotNull(b);
            List<T> ab = new List<T>(a.Count + b.Count);
            ab.AddRange(a);
            ab.AddRange(b);
            return ab;
        }
    }

    /// <summary>
    /// 简单的对一个列表的只读封装
    /// </summary>
    public class ReadOnlyList : ReadOnlyCollectionBase, IList
    {
        private IList innerList;

        public ReadOnlyList(IList innerList)
        {
            this.innerList = innerList;
        }

        public int Add(object value)
        {
            throw new NotSupportedException();
        }

        public void Clear()
        {
            throw new NotSupportedException();
        }

        public bool Contains(object value)
        {
            return innerList.Contains(value);
        }

        public int IndexOf(object value)
        {
            return innerList.IndexOf(value);
        }

        public void Insert(int index, object value)
        {
            throw new NotSupportedException();
        }

        public bool IsFixedSize
        {
            get { return true; }
        }

        public bool IsReadOnly
        {
            get { return true; }
        }

        public void Remove(object value)
        {
            throw new NotSupportedException();
        }

        public void RemoveAt(int index)
        {
            throw new NotSupportedException();
        }

        public object this[int index]
        {
            get
            {
                return innerList[index];
            }
            set
            {
                throw new NotSupportedException();
            }
        }
    }

    public class ReadOnlyList<T> : ReadOnlyCollectionBase, IList<T>
    {

        private IList<T> innerList;

        public ReadOnlyList(IList<T> innerList)
        {
            this.innerList = innerList;
        }

        public int IndexOf(T item)
        {
            return innerList.IndexOf(item);
        }

        public void Insert(int index, T item)
        {
            throw new NotSupportedException();
        }

        public void RemoveAt(int index)
        {
            throw new NotSupportedException();
        }

        public T this[int index]
        {
            get
            {
                return innerList[index];
            }
            set
            {
                throw new NotSupportedException();
            }
        }

        public void Add(T item)
        {
            throw new NotSupportedException();
        }

        public void Clear()
        {
            throw new NotSupportedException();
        }

        public bool Contains(T item)
        {
            return innerList.Contains(item);
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            innerList.CopyTo(array, arrayIndex);
        }

        public bool IsReadOnly
        {
            get { return true; }
        }

        public bool Remove(T item)
        {
            throw new NotSupportedException();
        }

        public new IEnumerator<T> GetEnumerator()
        {
            return innerList.GetEnumerator();
        }
    }

    public static class Collections2
    {

        public static bool ContainsAll<T>(this ICollection<T> thisCollection, ICollection<T> targets)
        {
            foreach (dynamic target in targets)
            {
                if (!thisCollection.Contains(target))
                {
                    return false;
                }
            }
            return true;
        }

        internal static bool SetEquals<T>(ISet<T> thisSet, object obj)
        {
            if (obj == thisSet)
            {
                return true;
            }
            if (obj is ISet<T>)
            {
                ISet<T> thatSet = (ISet<T>)obj;
                return thisSet.Count == thatSet.Count && thisSet.ContainsAll(thatSet);
            }
            return false;
        }
    }

    public static class Enumerators
    {
        /// <summary>
        /// 将source中指定元素映射为TResult元素的枚举。如果不希望将source中某个元素加入结果集，则func返回null即可
        /// </summary>
        public static IEnumerable<TResult> Map<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> func)
        {
            List<TResult> list = new List<TResult>();
            foreach (TSource s in source)
            {
                TResult r = func(s);
                if (r != null)
                    list.Add(r);
            }
            return list;
        }

        private class SingletonEnumerator<T> : IEnumerator<T>
        {
            private T value;

            private bool done = false;

            public SingletonEnumerator(T value)
            {
                this.value = value;
            }

            public T Current
            {
                get
                {
                    if (done)
                    {
                        throw new InvalidOperationException();
                    }
                    return value;
                }
            }

            public void Dispose()
            {

            }

            object System.Collections.IEnumerator.Current
            {
                get { return Current; }
            }

            public bool MoveNext()
            {
                done = true;
                return !done;
            }

            public void Reset()
            {
                done = false;
            }
        }

        public static IEnumerator<T> SingletonIterator<T>(T value)
        {
            return new SingletonEnumerator<T>(value);
        }
    }
}
